package com.lej.dataservice.club.http.base

import android.util.Base64
import java.io.UnsupportedEncodingException
import java.lang.reflect.Array
import java.security.NoSuchAlgorithmException
import java.security.SecureRandom
import javax.crypto.Cipher
import javax.crypto.KeyGenerator
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec

object AES {
    const val seed = "d2SpBidQuQA6ZLQX"

    private val CHAR_ENCODING = Charsets.UTF_8
    private const val ALGORITHM = "AES"
    private const val AES_ALGORITHM = "AES/CBC/PKCS5Padding"

    /**
     * 加密
     *
     * @param data 需要加密的内容
     * @param key  加密密码
     */
    fun encrypt(data: ByteArray?, key: ByteArray): ByteArray {
        notEmpty(data, "data")
        notEmpty(key, "key")
        if (key.size != 16) {
            throw RuntimeException("Invalid AES key length (must be 16 bytes)")
        }
        return try {
            val secretKey = SecretKeySpec(key, ALGORITHM)
            val enCodeFormat = secretKey.encoded
            val seckey = SecretKeySpec(enCodeFormat, ALGORITHM)
            val cipher = Cipher.getInstance(AES_ALGORITHM) // 创建密码器
            val iv = IvParameterSpec(key) //使用CBC模式，需要一个向量iv，可增加加密算法的强度
            cipher.init(Cipher.ENCRYPT_MODE, seckey, iv) // 初始化
            cipher.doFinal(data) // 加密
        } catch (e: Exception) {
            e.printStackTrace()
            throw RuntimeException("encrypt fail!", e)
        }
    }

    /**
     * 解密
     *
     * @param data 待解密内容
     * @param key  解密密钥
     * @return
     */
    fun decrypt(data: ByteArray?, key: ByteArray): ByteArray {
        notEmpty(data, "data")
        notEmpty(key, "key")
        if (key.size != 16) {
            throw RuntimeException("Invalid AES key length (must be 16 bytes)")
        }
        return try {
            val secretKey = SecretKeySpec(key, ALGORITHM)
            val enCodeFormat = secretKey.encoded
            val seckey = SecretKeySpec(enCodeFormat, ALGORITHM)
            val cipher = Cipher.getInstance(AES_ALGORITHM) // 创建密码器
            val iv = IvParameterSpec(key) //使用CBC模式，需要一个向量iv，可增加加密算法的强度
            cipher.init(Cipher.DECRYPT_MODE, seckey, iv) // 初始化
            cipher.doFinal(data) // 解密
        } catch (e: Exception) {
            e.printStackTrace()
            throw RuntimeException("decrypt fail!", e)
        }
    }

    fun encryptToBase64(data: String, key: String = seed): String {
        return try {
            val valueByte = encrypt(
                data.toByteArray(CHAR_ENCODING), key.toByteArray(CHAR_ENCODING)
            )
            String(Base64.encode(valueByte, Base64.NO_WRAP))
        } catch (e: UnsupportedEncodingException) {
            throw RuntimeException("encrypt fail!", e)
        }
    }

    fun decryptFromBase64(data: String, key: String = seed): String {
        return try {
            val originalData = Base64.decode(data.toByteArray(), Base64.NO_WRAP)
            val valueByte = decrypt(originalData, key.toByteArray(CHAR_ENCODING))
            String(valueByte, CHAR_ENCODING)
        } catch (e: UnsupportedEncodingException) {
            throw RuntimeException("decrypt fail!", e)
        }
    }

    fun encryptWithKeyBase64(data: String, key: String): String {
        return try {
            val valueByte = encrypt(
                data.toByteArray(CHAR_ENCODING),
                Base64.decode(key.toByteArray(), Base64.NO_WRAP)
            )
            String(Base64.encode(valueByte, Base64.NO_WRAP))
        } catch (e: UnsupportedEncodingException) {
            throw RuntimeException("encrypt fail!", e)
        }
    }

    fun decryptWithKeyBase64(data: String, key: String): String {
        return try {
            val originalData = Base64.decode(data.toByteArray(), Base64.NO_WRAP)
            val valueByte = decrypt(originalData, Base64.decode(key.toByteArray(), Base64.NO_WRAP))
            String(valueByte, CHAR_ENCODING)
        } catch (e: UnsupportedEncodingException) {
            throw RuntimeException("decrypt fail!", e)
        }
    }

    private fun generateRandomKey(): ByteArray {
        val keygen: KeyGenerator = try {
            KeyGenerator.getInstance(AES_ALGORITHM)
        } catch (e: NoSuchAlgorithmException) {
            throw RuntimeException("generateRandomKey fail!", e)
        }
        val random = SecureRandom()
        keygen.init(random)
        return keygen.generateKey().encoded
    }

    fun genarateRandomKeyWithBase64(): String {
        return String(Base64.encode(generateRandomKey(), Base64.NO_WRAP))
    }

    private fun notEmpty(obj: Any?, message: String) {
        requireNotNull(obj) { "$message must be specified" }
        require(!(obj is String && obj.toString().trim { it <= ' ' }
            .isEmpty())) { "$message must be specified" }
        require(!(obj.javaClass.isArray && Array.getLength(obj) == 0)) { "$message must be specified" }
        require(!(obj is Collection<*> && obj.isEmpty())) { "$message must be specified" }
        require(!(obj is Map<*, *> && obj.isEmpty())) { "$message must be specified" }
    }
}